In general terms, a computer program which is written by a programmer comprises a series of high-level, human-readable instructions. This set of instructions, commonly referred to as "source code", eventually controls a computer to perform preselected functions or tasks. However, human-readable source code is not in a form that is directly executable by the computer, and, therefore, it must be translated, by another program, called a "compiler", into a set of numbers called "object code" that can be executed by the computer. Object code may be combined with other resources to generate a program, referred to as an "executable program", which can be directly loaded and run by an operating system running on a computer. This program is often designated by an "exe" file extension.
Some prior art source programs consist of a single program file. However, the compilation of a source file of significant size is time consuming, especially with conventional highly-optimizing compilers which often make several passes through the entire file. With a single file, the entire program must be recompiled if any changes are made to any part of the program.
Consequently, it is common practice to divide the source program into smaller files, called source code "modules", each of which can be compiled separately. These modules commonly have a file extension which indicates the type of source code. For example, the file extension "c" denotes source code written in the C language, whereas a file extension "cpp" denotes source code written in the C++ language. In many cases, the object code modules are designated by an "obj" file extension. In this manner, a change to one module does not necessarily affect another module. Inevitably, there are references in one module to entities in another module. These references are handled after compilation of the modules is complete by another program called a "linker" which resolves all references and combines the modules into the finished executable program.
However, in some cases, a reference in a first source code module to an entity in a second source code module requires the first source code module to be recompiled if the second source code module is changed. This type of relationship is called a "dependency" and complicates the compilation and linking process because a change in one module may require recompilation of several other modules which depend on the changed module even though no changes have been made to these other modules.
The art has responded to this problem by using a "make" function to control the compiler. The make function keeps track of the dependencies and controls the compiler to recompile not only source code modules that were modified, but also other modules which depend on the changed modules. The make function is run every time changes are made to any module so that all dependent programs are properly recompiled.
A make function requires that the source code programmer also compose a specialized control file, known as a "makefile", which contains instructions that the make function uses to control the compilation and linking of each of the source code modules when the make function is executed. The makefile typically includes a hierarchy of source modules that embody the dependencies found in the program. For example, a makefile may include a variety of elements such as a series of instructions containing "targets", dependencies, and "shell commands" for updating the targets. Each of these makefile elements are explained in more detail below with reference to a segment of a simplified, exemplary makefile identified as MAKEFILE 1. A sample code fragment from MAKEFILE 1 is as follows:
______________________________________ (MAKEFILE 1) ______________________________________ foo.exe: foo.obj // BLOCK 1 icc -fefoo.exe foo.obj foo.obj: foo.cpp //BLOCK 2 icc -c foo.cpp . . //BLOCK N ______________________________________
The "target" of block 1 is the executable program "foo.exe" and the target of block 2 is the object code module "foo.obj." The executable program is formed by first compiling each target in the makefile and then linking the resulting object code files together in a predetermined order. In this case, "foo.exe" also is the executable program to be generated by the program development system and the shell command for linking the object files is icc-fefoo.exe foo.obj. For "foo.exe" to be generated, however, the underlying object code file "foo.obj" first must be compiled. The instructions for compiling "foo.obj" are in block 2. Shell command "icc -c foo.cpp" is the function to initiate this process. The compiler may also locate instructions for compiling other source code files, which instructions are stored in another part of the makefile (represented by the three ellipses). Once all of the target files have been compiled, they are linked together to form the executable program.
One problem with makefiles is that they are written for specific program development systems which, in turn, run on specific computer platforms. Numerous specialized versions of a single makefile therefore must be written so that the make function may be used for compiling the program on different types of platforms. This is time consuming and inefficient for the programmer. Further, any change to the program, such as the addition of a new source code module, requires the programmer to examine the dependencies and modify the makefile.
Accordingly, there is a need for an apparatus and method that enables a single source code file to be written, for use with the make command, that may be used across multiple types of computer platforms. It is among the general objects of the invention to provide such an apparatus and method.